home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / FS / DEVICES.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-17  |  8.5 KB  |  373 lines

  1. /*
  2.  *  linux/fs/devices.c
  3.  *
  4.  * (C) 1993 Matthias Urlichs -- collected common code and tables.
  5.  * 
  6.  *  Copyright (C) 1991, 1992  Linus Torvalds
  7.  *
  8.  *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
  9.  *  (changed to kmod)
  10.  */
  11.  
  12. #include <linux/config.h>
  13. #include <linux/fs.h>
  14. #include <linux/major.h>
  15. #include <linux/string.h>
  16. #include <linux/sched.h>
  17. #include <linux/stat.h>
  18. #include <linux/fcntl.h>
  19. #include <linux/errno.h>
  20. #ifdef CONFIG_KMOD
  21. #include <linux/kmod.h>
  22.  
  23. #include <linux/tty.h>
  24.  
  25. /* serial module kmod load support */
  26. struct tty_driver *get_tty_driver(kdev_t device);
  27. #define isa_tty_dev(ma)    (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
  28. #define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
  29. #endif
  30.  
  31. struct device_struct {
  32.     const char * name;
  33.     struct file_operations * fops;
  34. };
  35.  
  36. static struct device_struct chrdevs[MAX_CHRDEV] = {
  37.     { NULL, NULL },
  38. };
  39.  
  40. static struct device_struct blkdevs[MAX_BLKDEV] = {
  41.     { NULL, NULL },
  42. };
  43.  
  44. int get_device_list(char * page)
  45. {
  46.     int i;
  47.     int len;
  48.  
  49.     len = sprintf(page, "Character devices:\n");
  50.     for (i = 0; i < MAX_CHRDEV ; i++) {
  51.         if (chrdevs[i].fops) {
  52.             len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
  53.         }
  54.     }
  55.     len += sprintf(page+len, "\nBlock devices:\n");
  56.     for (i = 0; i < MAX_BLKDEV ; i++) {
  57.         if (blkdevs[i].fops) {
  58.             len += sprintf(page+len, "%3d %s\n", i, blkdevs[i].name);
  59.         }
  60.     }
  61.     return len;
  62. }
  63.  
  64. /*
  65.     Return the function table of a device.
  66.     Load the driver if needed.
  67. */
  68. static struct file_operations * get_fops(
  69.     unsigned int major,
  70.     unsigned int minor,
  71.     unsigned int maxdev,
  72.     const char *mangle,        /* String to use to build the module name */
  73.     struct device_struct tb[])
  74. {
  75.     struct file_operations *ret = NULL;
  76.  
  77.     if (major < maxdev){
  78. #ifdef CONFIG_KMOD
  79.         /*
  80.          * I do get request for device 0. I have no idea why. It happen
  81.          * at shutdown time for one. Without the following test, the
  82.          * kernel will happily trigger a request_module() which will
  83.          * trigger kmod and modprobe for nothing (since there
  84.          * is no device with major number == 0. And furthermore
  85.          * it locks the reboot process :-(
  86.          *
  87.          * Jacques Gelinas (jacques@solucorp.qc.ca)
  88.          *
  89.          * A. Haritsis <ah@doc.ic.ac.uk>: fix for serial module
  90.          *  though we need the minor here to check if serial dev,
  91.          *  we pass only the normal major char dev to kmod 
  92.          *  as there is no other loadable dev on these majors
  93.          */
  94.         if ((isa_tty_dev(major) && need_serial(major,minor)) ||
  95.             (major != 0 && !tb[major].fops)) {
  96.             char name[20];
  97.             sprintf(name, mangle, major);
  98.             request_module(name);
  99.         }
  100. #endif
  101.         ret = tb[major].fops;
  102.     }
  103.     return ret;
  104. }
  105.  
  106.  
  107. /*
  108.     Return the function table of a device.
  109.     Load the driver if needed.
  110. */
  111. struct file_operations * get_blkfops(unsigned int major)
  112. {
  113.     return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
  114. }
  115.  
  116. struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
  117. {
  118.     return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs);
  119. }
  120.  
  121. int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
  122. {
  123.     if (major == 0) {
  124.         for (major = MAX_CHRDEV-1; major > 0; major--) {
  125.             if (chrdevs[major].fops == NULL) {
  126.                 chrdevs[major].name = name;
  127.                 chrdevs[major].fops = fops;
  128.                 return major;
  129.             }
  130.         }
  131.         return -EBUSY;
  132.     }
  133.     if (major >= MAX_CHRDEV)
  134.         return -EINVAL;
  135.     if (chrdevs[major].fops && chrdevs[major].fops != fops)
  136.         return -EBUSY;
  137.     chrdevs[major].name = name;
  138.     chrdevs[major].fops = fops;
  139.     return 0;
  140. }
  141.  
  142. int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
  143. {
  144.     if (major == 0) {
  145.         for (major = MAX_BLKDEV-1; major > 0; major--) {
  146.             if (blkdevs[major].fops == NULL) {
  147.                 blkdevs[major].name = name;
  148.                 blkdevs[major].fops = fops;
  149.                 return major;
  150.             }
  151.         }
  152.         return -EBUSY;
  153.     }
  154.     if (major >= MAX_BLKDEV)
  155.         return -EINVAL;
  156.     if (blkdevs[major].fops && blkdevs[major].fops != fops)
  157.         return -EBUSY;
  158.     blkdevs[major].name = name;
  159.     blkdevs[major].fops = fops;
  160.     return 0;
  161. }
  162.  
  163. int unregister_chrdev(unsigned int major, const char * name)
  164. {
  165.     if (major >= MAX_CHRDEV)
  166.         return -EINVAL;
  167.     if (!chrdevs[major].fops)
  168.         return -EINVAL;
  169.     if (strcmp(chrdevs[major].name, name))
  170.         return -EINVAL;
  171.     chrdevs[major].name = NULL;
  172.     chrdevs[major].fops = NULL;
  173.     return 0;
  174. }
  175.  
  176. int unregister_blkdev(unsigned int major, const char * name)
  177. {
  178.     if (major >= MAX_BLKDEV)
  179.         return -EINVAL;
  180.     if (!blkdevs[major].fops)
  181.         return -EINVAL;
  182.     if (strcmp(blkdevs[major].name, name))
  183.         return -EINVAL;
  184.     blkdevs[major].name = NULL;
  185.     blkdevs[major].fops = NULL;
  186.     return 0;
  187. }
  188.  
  189. /*
  190.  * This routine checks whether a removable media has been changed,
  191.  * and invalidates all buffer-cache-entries in that case. This
  192.  * is a relatively slow routine, so we have to try to minimize using
  193.  * it. Thus it is called only upon a 'mount' or 'open'. This
  194.  * is the best way of combining speed and utility, I think.
  195.  * People changing diskettes in the middle of an operation deserve
  196.  * to loose :-)
  197.  */
  198. int check_disk_change(kdev_t dev)
  199. {
  200.     int i;
  201.     struct file_operations * fops;
  202.     struct super_block * sb;
  203.  
  204.     i = MAJOR(dev);
  205.     if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
  206.         return 0;
  207.     if (fops->check_media_change == NULL)
  208.         return 0;
  209.     if (!fops->check_media_change(dev))
  210.         return 0;
  211.  
  212.     printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
  213.         bdevname(dev));
  214.  
  215.     sb = get_super(dev);
  216.     if (sb && invalidate_inodes(sb))
  217.         printk("VFS: busy inodes on changed media.\n");
  218.  
  219.     invalidate_buffers(dev);
  220.  
  221.     if (fops->revalidate)
  222.         fops->revalidate(dev);
  223.     return 1;
  224. }
  225.  
  226. /*
  227.  * Called every time a block special file is opened
  228.  */
  229. int blkdev_open(struct inode * inode, struct file * filp)
  230. {
  231.     int ret = -ENODEV;
  232.     filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
  233.     if (filp->f_op != NULL){
  234.         ret = 0;
  235.         if (filp->f_op->open != NULL)
  236.             ret = filp->f_op->open(inode,filp);
  237.     }    
  238.     return ret;
  239. }    
  240.  
  241. int blkdev_release(struct inode * inode)
  242. {
  243.     struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
  244.     if (fops && fops->release)
  245.         return fops->release(inode,NULL);
  246.     return 0;
  247. }
  248.  
  249.  
  250. /*
  251.  * Dummy default file-operations: the only thing this does
  252.  * is contain the open that then fills in the correct operations
  253.  * depending on the special file...
  254.  */
  255. struct file_operations def_blk_fops = {
  256.     NULL,        /* lseek */
  257.     NULL,        /* read */
  258.     NULL,        /* write */
  259.     NULL,        /* readdir */
  260.     NULL,        /* poll */
  261.     NULL,        /* ioctl */
  262.     NULL,        /* mmap */
  263.     blkdev_open,    /* open */
  264.     NULL,        /* flush */
  265.     NULL,        /* release */
  266. };
  267.  
  268. struct inode_operations blkdev_inode_operations = {
  269.     &def_blk_fops,        /* default file operations */
  270.     NULL,            /* create */
  271.     NULL,            /* lookup */
  272.     NULL,            /* link */
  273.     NULL,            /* unlink */
  274.     NULL,            /* symlink */
  275.     NULL,            /* mkdir */
  276.     NULL,            /* rmdir */
  277.     NULL,            /* mknod */
  278.     NULL,            /* rename */
  279.     NULL,            /* readlink */
  280.     NULL,            /* readpage */
  281.     NULL,            /* writepage */
  282.     NULL,            /* bmap */
  283.     NULL,            /* truncate */
  284.     NULL            /* permission */
  285. };
  286.  
  287. /*
  288.  * Called every time a character special file is opened
  289.  */
  290. int chrdev_open(struct inode * inode, struct file * filp)
  291. {
  292.     int ret = -ENODEV;
  293.  
  294.     filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
  295.     if (filp->f_op != NULL){
  296.         ret = 0;
  297.         if (filp->f_op->open != NULL)
  298.             ret = filp->f_op->open(inode,filp);
  299.     }
  300.     return ret;
  301. }
  302.  
  303. /*
  304.  * Dummy default file-operations: the only thing this does
  305.  * is contain the open that then fills in the correct operations
  306.  * depending on the special file...
  307.  */
  308. struct file_operations def_chr_fops = {
  309.     NULL,        /* lseek */
  310.     NULL,        /* read */
  311.     NULL,        /* write */
  312.     NULL,        /* readdir */
  313.     NULL,        /* poll */
  314.     NULL,        /* ioctl */
  315.     NULL,        /* mmap */
  316.     chrdev_open,    /* open */
  317.     NULL,        /* flush */
  318.     NULL,        /* release */
  319. };
  320.  
  321. struct inode_operations chrdev_inode_operations = {
  322.     &def_chr_fops,        /* default file operations */
  323.     NULL,            /* create */
  324.     NULL,            /* lookup */
  325.     NULL,            /* link */
  326.     NULL,            /* unlink */
  327.     NULL,            /* symlink */
  328.     NULL,            /* mkdir */
  329.     NULL,            /* rmdir */
  330.     NULL,            /* mknod */
  331.     NULL,            /* rename */
  332.     NULL,            /* readlink */
  333.     NULL,            /* readpage */
  334.     NULL,            /* writepage */
  335.     NULL,            /* bmap */
  336.     NULL,            /* truncate */
  337.     NULL            /* permission */
  338. };
  339.  
  340. /*
  341.  * Print device name (in decimal, hexadecimal or symbolic)
  342.  * Note: returns pointer to static data!
  343.  */
  344. char * kdevname(kdev_t dev)
  345. {
  346.     static char buffer[32];
  347.     sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
  348.     return buffer;
  349. }
  350.  
  351. char * bdevname(kdev_t dev)
  352. {
  353.     static char buffer[32];
  354.     const char * name = blkdevs[MAJOR(dev)].name;
  355.  
  356.     if (!name)
  357.         name = "unknown-block";
  358.  
  359.     sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
  360.     return buffer;
  361. }
  362.  
  363. char * cdevname(kdev_t dev)
  364. {
  365.     static char buffer[32];
  366.     const char * name = chrdevs[MAJOR(dev)].name;
  367.  
  368.     if (!name)
  369.         name = "unknown-char";
  370.     sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
  371.     return buffer;
  372. }
  373.